package top.littlejiang.onlinexam.websocket.wsserver;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import top.littlejiang.onlinexam.common.utils.JWTUtils;
import top.littlejiang.onlinexam.common.utils.RedisUtils;
import top.littlejiang.onlinexam.common.utils.UUIDUtil;
import top.littlejiang.onlinexam.websocket.common.Message;
import top.littlejiang.onlinexam.websocket.common.WsConstant;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author chen
 * @since 2020/7/3
 */
@Slf4j
@Component
@ServerEndpoint(value = "/wsserver/{token}/{examUuid}")
public class WsServe {

    private Session session;
    private Integer userId;
    private String examUuid;
    private String userRole;

    /**
     * session缓存：存储客户端的所有连接
     */
    private static ConcurrentHashMap<String, WsServe> clients = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token, @PathParam("examUuid") String examUuid) {
        this.session = session;
        this.userId = JWTUtils.getUserId(token);
        this.examUuid = examUuid;
        this.userRole = JWTUtils.getUserRole(token);
        log.info(userId.toString() + JWTUtils.getUserName(token) + "用户上线");

        //clients中添加连接的客户端
        clients.put(userId.toString(), this);

        if (WsConstant.TEACHER_SIGN.equals(this.userRole)) {
            RedisUtils.hset(WsConstant.TEACHER_PREFIX + examUuid, userId.toString(), UUIDUtil.getUUID());
        } else if (WsConstant.STUDENT_SIGN.equals(this.userRole)) {
            RedisUtils.hset(WsConstant.STUDENT_PREFIX + examUuid, userId.toString(), UUIDUtil.getUUID());
        }

    }


    /**
     * 私发消息
     * @param data
     */
    private void sendTo(String data) {

        //创建Message对象
        Message message = new Message();
        message.setHead(WsConstant.SEND_TO_HEADER);


        //解析客户端消息重新组装后发出去
        JSONObject jsonObject = JSON.parseObject(data);
        String toUser = jsonObject.getString("toUser");
        String fromUser = jsonObject.getString("fromUser");

        message.setData(JSON.toJSONString(jsonObject));

        //发送消息
        String messageStr = JSON.toJSONString(message);

        WsServe wsServe = clients.get(toUser);
        if (!Objects.isNull(wsServe)){
            synchronized(wsServe.session){
                try {
                    wsServe.session.getBasicRemote().sendText(messageStr);
                } catch (IOException e) {
                    log.error("sendTo 发送错误 {}", e);
                }
            }
        }
    }

    @OnMessage
    public void onMessage(String message) {
        log.info("接收到消息了" + message);
        //解析消息
        JSONObject jsonObject = JSON.parseObject(message);
        String head = jsonObject.getString("head");
        String data = jsonObject.getString("data");
        if(WsConstant.SEND_TO_HEADER.equals(head)) {
            //私发消息
            sendTo(data);
        } else if (WsConstant.VIDEO_CALL_HEADER.equals(head)) {
            //视频通话
            videoCall(message);
        }
    }

    private void videoCall(String message) {
        JSONObject jsonObject = JSON.parseObject(message);
        String toUser = jsonObject.getObject("data", JSONObject.class).getString("toUser");
        String fromUser = jsonObject.getString("fromUser");
        WsServe server = clients.get(toUser);
        if (!Objects.isNull(server)){
            synchronized (server.session) {
                try {
                    server.session.getBasicRemote().sendText(message);
                } catch (Exception e) {
                    log.error("videoCall视频传输错误：{}",e);
                }
            }
        }

    }

    @OnClose
    public void onClose() {
        if (WsConstant.TEACHER_SIGN.equals(this.userRole)) {
            RedisUtils.hdel(WsConstant.TEACHER_PREFIX + examUuid, userId.toString());
        } else if (WsConstant.STUDENT_SIGN.equals(this.userRole)) {
            RedisUtils.hdel(WsConstant.STUDENT_PREFIX + examUuid, userId.toString());
        }
        log.info(this.userId + "关闭连接");
    }

    @OnError
    public void onError(Throwable throwable) {
        log.error("websocket 错误", throwable);
    }
}

